package com.itwn.portal.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itwn.common.constant.RedisConst;
import com.itwn.portal.common.enums.UserStatus;
import com.itwn.portal.common.exception.Asserts;
import com.itwn.portal.common.exception.BookBusinessException;
import com.itwn.portal.common.result.BusinessCode;
import com.itwn.portal.model.entity.User;
import com.itwn.portal.model.vo.LoginRequest;
import com.itwn.portal.model.vo.RegisterRequest;
import com.itwn.portal.model.vo.UserVo;
import com.itwn.portal.service.UserService;
import com.itwn.portal.mapper.UserMapper;
import com.itwn.portal.util.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
* @author 61073
* @description 针对表【t_user】的数据库操作Service实现
* @createDate 2024-12-10 15:34:38
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public UserVo login(LoginRequest param) {
        // 从Redis中获取验证码
        String code = (String) redisTemplate.opsForValue().get(param.getKey());
        Asserts.error(Objects.isNull(code),BusinessCode.INVALID_VERIFICATION);
        Asserts.error(!code.equalsIgnoreCase(param.getCode()),BusinessCode.INVALID_VERIFICATION);
        // 删除Redis中的验证码
        redisTemplate.delete(param.getKey());

        // 1. 校验用户名是否存在
        User user = this.getOne(
                Wrappers.lambdaQuery(User.class)
                        .eq(User::getAccount, param.getAccount()));
        Asserts.error(Objects.isNull(user),BusinessCode.USER_NOT_EXIST);

        // 2. 校验密码是否正确
        boolean matches = passwordEncoder.matches(param.getPassword(), user.getPassword());
        Asserts.error(!matches,BusinessCode.PASSWORD_ERROR);

        // 3. 校验用户状态是否可用
        Asserts.error(UserStatus.ACTIVE.getKey() != user.getState(),BusinessCode.USER_FROZEN_ERROR);

        UserVo userVo = createUserVo(user);

        return userVo;
    }

    private UserVo createUserVo(User user) {
        //1. 生成token
        Map<String, Object> data = new HashMap<>();
        data.put("id", user.getId());
        data.put("userName", user.getAccount());
        data.put("ip",jwtUtil.getRequestIP(request)); // 确保生成token与使用token是同一个ip
        String token = jwtUtil.createToken(data);

        //2. 存储token到Redis中
        redisTemplate.opsForValue().set(
                RedisConst.USER_TOKEN_PREFIX + ":" + user.getId(),
                token,
                Duration.ofDays(1)
        );

        //3. 构造UserVo对象
        // cn.hutool.core.bean.BeanUtil
        UserVo userVo = BeanUtil.copyProperties(user, UserVo.class);
        userVo.setToken(token);
        return userVo;
    }


    @Cacheable(value = RedisConst.USER_DETAIL, keyGenerator = "keyGenerator")
    @Override
    public User findById(long id) {
        return this.getById(id);
    }

    @Override
    public UserVo smsLogin(LoginRequest param) {
        // 获取Redis中验证码
        String key = RedisConst.SHORT_MESSAGE_SERVICE + ":" + param.getTelephone();
        String redisCode = (String) redisTemplate.opsForValue().get(key);
        // 验证码校验：过期？ 输入是否正确？
        Asserts.error(Objects.isNull(redisCode), BusinessCode.INVALID_VERIFICATION);
        Asserts.error(!redisCode.equalsIgnoreCase(param.getCode()), BusinessCode.VERIFICATION_ERROR);
        // 删除验证码
        redisTemplate.delete(key);

        // 根据手机号码+验证码登录， 手机号不存在，就自动注册
        User user = this.getOne(
                Wrappers.lambdaQuery(User.class)
                        .eq(User::getMobile, param.getTelephone()));
        // 判断：账号如果存在，且处于冻结状态，返回错误
        Asserts.error(
                Objects.nonNull(user) && UserStatus.ACTIVE.getKey() != user.getState(),
                BusinessCode.USER_FROZEN_ERROR);

        if (Objects.isNull(user)) {
            user = new User();
            user.setMobile(param.getTelephone());
            user.setAccount(param.getTelephone());
            user.setPassword(passwordEncoder.encode("123"));
            user.setNickname(param.getTelephone());
            user.setRealName(param.getTelephone());
            user.setState(UserStatus.ACTIVE.getKey());
            this.save(user); // 自动注册
        }

        // 创建UserVo并返回
        UserVo userVo = createUserVo(user);
        return userVo;
    }


    /**
     * 判断账户名是否存在
     */
    @Override
    public boolean isAccountExist(String account) {
        LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class).eq(User::getAccount, account);
        return baseMapper.selectOne(wrapper)!= null;
    }

    /**
     * 判断电话是否存在
     */
    @Override
    public boolean isMobileExist(String mobile) {
        LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class)
                .eq(User::getMobile, mobile);
        return baseMapper.selectOne(wrapper)!= null;
    }


    /**
     * 注册成功，返回新的用户对象
     */
    @Override
    public UserVo register(RegisterRequest request) {
        //1. 校验邮箱验证码：过期？ 输入正确？
        String key = RedisConst.EMAIL_ADDRESS_PREFIX + ":" + request.getEmail();
        Object emailCode = redisTemplate.opsForValue().get(key);
        Asserts.error(Objects.isNull(emailCode), BusinessCode.INVALID_VERIFICATION);
        Asserts.error(!emailCode.toString().equalsIgnoreCase(request.getValidCode()), BusinessCode.VERIFICATION_ERROR);

        //2. 校验账号必须唯一
        Asserts.error(isAccountExist(request.getAccount()), BusinessCode.USER_IS_EXIST);

        //3. 手机号必须唯一
        Asserts.error(isMobileExist(request.getMobile()), BusinessCode.MOBILE_IS_EXIST);

        //4. 注册
        User user = BeanUtil.copyProperties(request, User.class);
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        user.setState(UserStatus.ACTIVE.getKey());
        baseMapper.insert(user);

        //5. 创建UserVo对象并返回
        UserVo userVo = createUserVo(user);
        return userVo;
    }
}




